package com.niiwoo.civet.mobile.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.account.dto.common.BankCardDTO;
import com.niiwoo.civet.account.dto.common.BankCardRebindOrderDTO;
import com.niiwoo.civet.account.dto.common.BankTypeDTO;
import com.niiwoo.civet.account.dto.request.InitBankCardRebindOrderRequestDTO;
import com.niiwoo.civet.account.dto.response.AccountBaseResponse;
import com.niiwoo.civet.account.dto.response.GetSimpleUserBankCardResponse;
import com.niiwoo.civet.account.dto.response.PayChannelBankResponseDTO;
import com.niiwoo.civet.account.dto.response.RebindBankCardCheckResponse;
import com.niiwoo.civet.account.service.AccountDubboService;
import com.niiwoo.civet.account.service.PayChannelBankDubboService;
import com.niiwoo.civet.account.service.UserBankCardToDecodeDubboService;
import com.niiwoo.civet.account.service.bankcard.BankCardDubboService;
import com.niiwoo.civet.base.constant.OrgConstant;
import com.niiwoo.civet.mobile.util.R360RedisService;
import com.niiwoo.civet.mobile.vo.common.BankCardRebindCheckVO;
import com.niiwoo.civet.mobile.vo.common.BankCardVO;
import com.niiwoo.civet.mobile.vo.common.BankTypeVO;
import com.niiwoo.civet.mobile.vo.common.FormVO;
import com.niiwoo.civet.mobile.vo.request.GetSupportBankTypeListRequestVO;
import com.niiwoo.civet.mobile.vo.request.GetThirdTokenRequestVO;
import com.niiwoo.civet.mobile.vo.request.GetUserBankCardRequestVO;
import com.niiwoo.civet.mobile.vo.request.bankcard.GetBankTypeByCardBinNoRequestVO;
import com.niiwoo.civet.mobile.vo.request.bankcard.RebindBankCardSubmitRequestVO;
import com.niiwoo.civet.mobile.vo.request.bankcard.RebindBankCardUploadFileRequestVO;
import com.niiwoo.civet.mobile.vo.response.GetThirdTokenResponseVO;
import com.niiwoo.civet.mobile.vo.response.bankcard.*;
import com.niiwoo.civet.trade.enums.TradeConfigEnum;
import com.niiwoo.civet.trade.service.configure.TradeConfigDubboService;
import com.niiwoo.civet.user.service.OrganizationDubboService;
import com.niiwoo.tripod.base.utils.EmojiFilter;
import com.niiwoo.tripod.base.utils.MD5SignUtil;
import com.niiwoo.tripod.consumer.component.FileUploadHandler;
import com.niiwoo.tripod.lanmao.component.LanMaoGatewayService;
import com.niiwoo.tripod.lanmao.enums.UserDeviceEnum;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.lanmao.request.PersonalBindBankCardExpandRequest;
import com.niiwoo.tripod.lanmao.response.LanMaoGatewayDTO;
import com.niiwoo.tripod.web.annotation.AuthIgnore;
import com.niiwoo.tripod.web.util.PrincipalContext;
import com.niiwoo.tripod.web.vo.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Created by wangjichao on 2017/10/16.
 */
@RestController
@RequestMapping("/bankcard")
@Api(tags = "银行卡", description = "/bankcard")
@Slf4j
public class BankCardController {

    @Reference(version = "1.0.0")
    private BankCardDubboService bankCardDubboService;

    @Reference(version = "1.0.0")
    private TradeConfigDubboService tradeConfigDubboService;

    @Reference(version = "1.0.0")
    private UserBankCardToDecodeDubboService userBankCardToDecodeDubboService;

    @Reference(version = "1.0.0")
    OrganizationDubboService organizationDubboService;

    @Autowired
    private LanMaoGatewayService lanMaoGatewayService;

    @Autowired
    private FileUploadHandler fileUploadHandler;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    R360RedisService r360RedisService;

    @Value("${h5-https-url}")
    private String h5HttpsUrl;

    @Reference(version = "1.0.0")
    private AccountDubboService accountDubboService;
    @Reference(version = "1.0.0")
    private PayChannelBankDubboService payChannelBankDubboService;

    @PostMapping("/getToken")
    @ApiOperation("获取TOKEN")
    @AuthIgnore
    public Result<GetThirdTokenResponseVO> getToken(@RequestBody GetThirdTokenRequestVO getThirdTokenRequestVO) {
        // 将签名加入缓存中，并设置5分钟过期时间，用于签名过期认证
        String signature = MD5SignUtil.create(Collections.singletonMap("userId", getThirdTokenRequestVO.getUserId()), "0000");
        redisTemplate.opsForValue().set("org:account-register:".concat(signature), getThirdTokenRequestVO.getUserId(), 10, TimeUnit.MINUTES);
        GetThirdTokenResponseVO responseVO = new GetThirdTokenResponseVO();
        responseVO.setToken(signature);
        return Result.with(responseVO);
    }

    @PostMapping("/getSupportBankTypeList/h5")
    @ApiOperation("获取支持的银行类型列表h5")
    @AuthIgnore
    public Result<GetSupportBankTypeListResponseVO> getSupportBankTypeListH5(@RequestBody GetSupportBankTypeListRequestVO requestVO) {
        log.info("获取支持的银行类型列表h5,请求参数={}", JSON.toJSONString(requestVO));
        validThirdToken(requestVO.getToken(),requestVO.getChannel());
        return getSupportBankTypeList();
    }

    @PostMapping("/getSupportBankTypeList")
    @ApiOperation("获取支持的银行类型列表")
    public Result<GetSupportBankTypeListResponseVO> getSupportBankTypeList() {
        GetSupportBankTypeListResponseVO response = new GetSupportBankTypeListResponseVO();
        List<BankTypeVO> bankTypeVOList = new ArrayList<BankTypeVO>();
        BankTypeVO bankTypeVO;
        List<BankTypeDTO> bankTypeDTOList = bankCardDubboService.getSupportBankTypeList();
        for (BankTypeDTO bankTypeDTO : bankTypeDTOList) {
            bankTypeVO = new BankTypeVO();
            bankTypeVO.setBankTypeId(bankTypeDTO.getBankTypeId());
            bankTypeVO.setBankCode(bankTypeDTO.getBankCode());
            bankTypeVO.setBankName(bankTypeDTO.getBankName());
            bankTypeVO.setSequence(bankTypeDTO.getSequence());
            bankTypeVO.setIsSupportWithhold(bankTypeDTO.getIsSupportWithhold());
            bankTypeVO.setIsMaintain(bankTypeDTO.getIsMaintain());
            bankTypeVO.setIsRecommend(bankTypeDTO.getIsRecommend());
            PayChannelBankResponseDTO payChannelBankResponseDTO = payChannelBankDubboService.getOptimalPayChannelBankByBankType(bankTypeDTO.getBankTypeId());
            if( null != payChannelBankResponseDTO ){
                bankTypeVO.setADealMaxAmount(payChannelBankResponseDTO.getMaxAmountPerTrade());
                bankTypeVO.setDayMaxAmount(payChannelBankResponseDTO.getMaxAmountPerDay());
                bankTypeVO.setMonthMaxAmount(payChannelBankResponseDTO.getMaxAmountPerMonth());
            }

            bankTypeVOList.add(bankTypeVO);
        }
        response.setBankTypeList(bankTypeVOList);
        return Result.with(response);
    }

    @PostMapping("/getBankTypeByCardBinNo/h5")
    @ApiOperation("根据卡号查询卡bin获取银行类型")
    @AuthIgnore
    public Result<GetBankTypeByCardBinNoResponseVO> getBankTypeByCardBinNoH5(@RequestBody @Valid GetBankTypeByCardBinNoRequestVO request){
        validThirdToken(request.getToken(),request.getChannel());
        return getBankTypeByCardBinNo(request);
    }

    @PostMapping("/getBankTypeByCardBinNo")
    @ApiOperation("根据卡号查询卡bin获取银行类型")
    public Result<GetBankTypeByCardBinNoResponseVO> getBankTypeByCardBinNo(@RequestBody @Valid GetBankTypeByCardBinNoRequestVO request) {
        GetBankTypeByCardBinNoResponseVO response = new GetBankTypeByCardBinNoResponseVO();
        BankTypeVO bankTypeVO = null;
        BankTypeDTO bankTypeDTO = bankCardDubboService.getBankTypeByCardBinNo(request.getCardBinNo());
        if (bankTypeDTO != null) {
            bankTypeVO = new BankTypeVO();
            bankTypeVO.setBankTypeId(bankTypeDTO.getBankTypeId());
            bankTypeVO.setBankCode(bankTypeDTO.getBankCode());
            bankTypeVO.setBankName(bankTypeDTO.getBankName());
            bankTypeVO.setSequence(bankTypeDTO.getSequence());
        }
        response.setBankType(bankTypeVO);
        return Result.with(response);
    }

    @PostMapping("/getUserBankCard/h5")
    @ApiOperation("获取用户绑定的银行卡数据H5")
    @AuthIgnore
    public Result<GetUserBankCardResponseVO> getUserBankCardH5(@RequestBody GetUserBankCardRequestVO getUserBankCardRequestVO) {
        String userId = validThirdToken(getUserBankCardRequestVO.getToken(),getUserBankCardRequestVO.getChannel());
        // 机构ID
        String orgId;
        // 第三方渠道为机构极速借
        if(Objects.equals(R360RedisService.ThirdPart.ORG.getChannel(), getUserBankCardRequestVO.getChannel())) {
            orgId = organizationDubboService.loadValidOrgId(getUserBankCardRequestVO.getOrgCode());
        }else{
            orgId = OrgConstant.NIIWOO_ORG_ID;
        }
        return doGetUserBankCard(userId,orgId);
    }

    @PostMapping("/getUserBankCard")
    @ApiOperation("获取用户绑定的银行卡数据")
    public Result<GetUserBankCardResponseVO> getUserBankCard() {
        return doGetUserBankCard(PrincipalContext.getUserId(),OrgConstant.NIIWOO_ORG_ID);
    }

    private Result<GetUserBankCardResponseVO> doGetUserBankCard(String userId,String orgId) {
        GetUserBankCardResponseVO getUserBankCardResponseVO = new GetUserBankCardResponseVO();
        BankCardRebindCheckVO rebindCheckVO = new BankCardRebindCheckVO();
        BankCardVO bankCardVO = null;
        BankTypeVO bankTypeVO = null;
        //银行卡基本数据
        GetSimpleUserBankCardResponse serviceResponse = bankCardDubboService.getSimpleUserBankCard(userId,orgId);
        BankCardDTO bankCardDTO = serviceResponse.getBankCard();
        if (bankCardDTO != null) {
            bankCardVO = new BankCardVO();
            bankCardVO.setBankCardId(bankCardDTO.getBankCardId());
            bankCardVO.setBankAccountNo(bankCardDTO.getBankAccountNo());
            bankCardVO.setIdCardNo(bankCardDTO.getIdCard());
            bankCardVO.setRealName(bankCardDTO.getRealName());
            bankCardVO.setMobileNo(bankCardDTO.getMobileNo());

            BankTypeDTO bankTypeDTO = bankCardDTO.getBankType();
            if (bankTypeDTO != null) {
                bankTypeVO = new BankTypeVO();
                bankTypeVO.setBankTypeId(bankTypeDTO.getBankTypeId());
                bankTypeVO.setBankCode(bankTypeDTO.getBankCode());
                bankTypeVO.setBankName(bankTypeDTO.getBankName());
                bankTypeVO.setIsSupportWithhold(bankTypeDTO.getIsSupportWithhold());
            }
            bankCardVO.setBankType(bankTypeVO);
        }

        //OCR开关
        List<TradeConfigEnum> enumList = new ArrayList<>();
        enumList.add(TradeConfigEnum.OCRSCANBANKCARDSWITCH);
        Map<String, String> configMap = tradeConfigDubboService.selectTradeConfigByEmuns(enumList);
        String ocrSwitch = configMap.get(TradeConfigEnum.OCRSCANBANKCARDSWITCH.getConfigKey());

        //查询换绑卡检查
        RebindBankCardCheckResponse rebindBankCardCheckResponse = bankCardDubboService.rebindBankCardCheck(userId,orgId);
        rebindCheckVO.setForbidRebind(rebindBankCardCheckResponse.getForbidRebind());
        rebindCheckVO.setRequireUpload(rebindBankCardCheckResponse.getRequireUpload());
        if (rebindBankCardCheckResponse.getForbidRebind()) {
            rebindCheckVO.setForbidRebindReasonCode(rebindBankCardCheckResponse.getRebindForbidReasonEnum().getValue());
            rebindCheckVO.setForbidRebindReasonMsg(rebindBankCardCheckResponse.getRebindForbidReasonEnum().getDesc());
        }

        getUserBankCardResponseVO.setBankCard(bankCardVO);
        getUserBankCardResponseVO.setBankCardOcrSwitch(StringUtils.isEmpty(ocrSwitch) ? 0 : Byte.valueOf(ocrSwitch));
        getUserBankCardResponseVO.setRebindCheck(rebindCheckVO);
        getUserBankCardResponseVO.setExpectAuditTime(serviceResponse.getExpectAuditTime());
        getUserBankCardResponseVO.setExpectAuditTimeIsToday(serviceResponse.getExpectAuditTimeIsToday());
        getUserBankCardResponseVO.setHasRebindApply(serviceResponse.isHasRebindApply());
        getUserBankCardResponseVO.setIsSupportWithhold(serviceResponse.isSupportWithhold());

        // 还款服务委托书(已开通借款账户时才需要展示)
        if (OrgConstant.NIIWOO_ORG_ID.equals(orgId)) {
            AccountBaseResponse borrowAccount = accountDubboService.getNiiwooAccount(userId, UserRoleEnum.BORROWERS);
            if (borrowAccount != null) {
                //String withholdContractUrl = h5HttpsUrl + "/html5/project/niiwoo-contract/repayAgreement.html";
                //5.5.0地址改变
                String withholdContractUrl = h5HttpsUrl + "/html5/contract/repayAgreement.html";
                getUserBankCardResponseVO.setWithholdContractUrl(withholdContractUrl);
            }
        }

        return Result.with(getUserBankCardResponseVO);
    }

    @PostMapping("/rebindBankCardUploadFile/h5")
    @ApiOperation("换绑银行卡上传附件")
    @AuthIgnore
    public Result<RebindBankCardUploadFileResponseVO> rebindBankCardUploadFileH5(@RequestBody @Valid RebindBankCardUploadFileRequestVO request){
        validThirdToken(request.getToken(),request.getChannel());
        return rebindBankCardUploadFile(request);
    }

    @PostMapping("/rebindBankCardUploadFile")
    @ApiOperation("换绑银行卡上传附件")
    public Result<RebindBankCardUploadFileResponseVO> rebindBankCardUploadFile(@RequestBody @Valid RebindBankCardUploadFileRequestVO request) {
        RebindBankCardUploadFileResponseVO response = new RebindBankCardUploadFileResponseVO();
        String imageFile = request.getBase64Image();
        byte[] imageBytes = Base64.decodeBase64(imageFile);
        String fileUrl = fileUploadHandler.upload(imageBytes, false).getImageUrl();
        response.setFileUrl(fileUrl);
        return Result.with(response);
    }

    @PostMapping("/rebindBankCardSubmit/h5")
    @ApiOperation("换绑银行卡保存申请H5")
    @AuthIgnore
    public Result<RebindBankCardSubmitResponseVO> rebindBankCardSubmitH5(@RequestBody @Valid RebindBankCardSubmitRequestVO request){
        String userId = validThirdToken(request.getToken(),request.getChannel());
        return doRebindBankCardSubmit(userId,request);
    }

    @PostMapping("/rebindBankCardSubmit")
    @ApiOperation("换绑银行卡保存申请")
    public Result<RebindBankCardSubmitResponseVO> rebindBankCardSubmit(@RequestBody @Valid RebindBankCardSubmitRequestVO request) {
        String userId = PrincipalContext.getUserId();
        return doRebindBankCardSubmit(userId,request);
    }

    private Result<RebindBankCardSubmitResponseVO> doRebindBankCardSubmit(String userId,RebindBankCardSubmitRequestVO request){
        RebindBankCardSubmitResponseVO response = new RebindBankCardSubmitResponseVO();
        //初始化换绑卡订单
        InitBankCardRebindOrderRequestDTO serviceRequest = new InitBankCardRebindOrderRequestDTO();
        serviceRequest.setUserId(userId);
        serviceRequest.setMobileNo(request.getMobileNo());
        serviceRequest.setBankTypeId(request.getBankTypeId());
        serviceRequest.setBankAccountNo(request.getBankAccountNo());
        serviceRequest.setUserDesc(EmojiFilter.filterEmoji(request.getUserDesc()));//过滤表情
        serviceRequest.setFileUrls(request.getFileUrls());

        // 第三方渠道为机构极速借
        if(Objects.equals(R360RedisService.ThirdPart.ORG.getChannel(), request.getChannel())) {
            serviceRequest.setOrgId(organizationDubboService.loadValidOrgId(request.getOrgCode()));
        }else{
            serviceRequest.setOrgId(OrgConstant.NIIWOO_ORG_ID);
        }
        BankCardRebindOrderDTO bankCardRebindOrderDTO = bankCardDubboService.initBankCardRebindOrder(serviceRequest);

        //调用存管组件生成表单
        PersonalBindBankCardExpandRequest lanmaoRequest = new PersonalBindBankCardExpandRequest();
        lanmaoRequest.setRequestNo(bankCardRebindOrderDTO.getRequestNo());
        lanmaoRequest.setBankcardNo(bankCardRebindOrderDTO.getBankAccountNo());
        lanmaoRequest.setMobile(bankCardRebindOrderDTO.getMobileNo());
        lanmaoRequest.setExpired(bankCardRebindOrderDTO.getExpireTime());
        lanmaoRequest.setNiiwooRedirectUrl(request.getRedirectUrl());
        lanmaoRequest.setPlatformUserNo(bankCardRebindOrderDTO.getAccountNo());
        lanmaoRequest.setUserDevice(UserDeviceEnum.MOBILE);
        lanmaoRequest.setTimestamp(new Date());
        LanMaoGatewayDTO lanMaoGatewayDTO = lanMaoGatewayService.personalBindBankCardExpand(lanmaoRequest);

        FormVO formVO = new FormVO();
        formVO.setAction(lanMaoGatewayDTO.getAction());
        formVO.setParams(lanMaoGatewayDTO.getParams());
        response.setForm(formVO);

        return Result.with(response);
    }

    /**
     * 验证第三方TOKEN
     *
     * @param token
     * @param channel
     * @return
     */
    private String validThirdToken(String token,Integer channel){
        String userId;
        if (channel == null) {
            userId = r360RedisService.verifyTokenAndGetUserId(token);
        } else {
            userId = r360RedisService.verifyTokenAndGetUserId(token, channel);
        }
        return userId;
    }

    @AuthIgnore
    @PostMapping("/userInitMLyPdFkU2tWq0gPndvuxMum9VxGLIiyT")
    @ApiOperation("临时转换用户数据入口")
    public void toTransformTempUserExport(){
        userBankCardToDecodeDubboService.toTransformTempUserExport();
    }
}
